# -*- coding: utf-8 -*-
import random
import threading
import time

condition = threading.Condition()
queue = []
MAX_QUEUE_SIZE = 10


def producer():
    while True:
        with condition:
            while len(queue) == MAX_QUEUE_SIZE:
                condition.wait()
            data = random.randint(1, 100)
            queue.append(data)
            print(f"Produced: {data}")
            condition.notify()
        time.sleep(random.uniform(0.5, 2))
        print(f"===========queue: {queue}")


def consumer():
    while True:
        with condition:
            while not queue:
                condition.wait()
            data = queue.pop(0)
            print(f"Consumed: {data}")
            condition.notify()
        time.sleep(random.uniform(0.5, 2))


def producer_consumer():
    producer_thread = threading.Thread(target=producer)
    consumer_thread = threading.Thread(target=consumer)

    producer_thread.start()
    consumer_thread.start()

    producer_thread.join()
    consumer_thread.join()


class ProducerThread(threading.Thread):
    MAX_QUEUE_SIZE = 10

    def __init__(self, _condition, _queue):
        super().__init__()
        self._queue = _queue
        self._condition = _condition

    def run(self) -> None:
        while True:
            with self._condition:
                if len(self._queue) >= self.MAX_QUEUE_SIZE:
                    self._condition.wait()
                data = random.randint(0, 100)
                print(f"Produced: {data}")
                self._queue.append(data)
                self._condition.notify()
                time.sleep(random.uniform(0.5, 2))


class ConsumerThread(threading.Thread):
    def __init__(self, _condition, _queue):
        super().__init__()
        self._condition = _condition
        self._queue = _queue

    def run(self):
        while True:
            with self._condition:
                if len(self._queue) == 0:
                    self._condition.wait()
                data = self._queue.pop(0)
                print(f"Consumed: {data}")
                self._condition.notify()
                time.sleep(random.uniform(0.5, 2))


def custom_thread_test():
    producer_thread = ProducerThread(condition, queue)
    consumer_thread = ConsumerThread(condition, queue)
    producer_thread.start()
    consumer_thread.start()
    producer_thread.join()
    consumer_thread.join()


class PeriodicTimer:
    def __init__(self, interval):
        self._interval = interval
        self._flag = 0
        self._cv = threading.Condition()

    def start(self):
        t = threading.Thread(target=self.run)
        t.daemon = True
        t.start()

    def run(self):
        while True:
            time.sleep(self._interval)
            with self._cv:
                self._flag ^= 1
                # print(f"Flag: {self._flag}")
                self._cv.notify()

    def wait_for_tick(self):
        with self._cv:
            last_flag = self._flag
            while self._flag == last_flag:
                self._cv.wait()


def count_down(ticks, timer):
    while ticks > 0:
        timer.wait_for_tick()
        print(f"Ticks: {ticks}")
        ticks -= 1


def count_up(last, timer):
    n = 0
    while n <= last:
        timer.wait_for_tick()
        print("Counting", n)
        n += 1


def timer_test():
    ptimer = PeriodicTimer(5)
    ptimer.start()
    threading.Thread(target=count_down, args=(10, ptimer)).start()
    threading.Thread(target=count_up, args=(5, ptimer)).start()


if __name__ == '__main__':
    # custom_thread_test()
    timer_test()
